#include <gtest/gtest.h>
#include <string>
#include "windows/security/cx_sddl.h" 
#include "cx_string/cx_string.h"
#include "constants.h"

using namespace CXLib;
using namespace CXLib::CXSddl;

TEST(CxSDDLTest, GetHIDPathSDDL) {
    
    auto hidsSddl = cxGetHIDsACL(0, TARGET_VID);

    const std::string targetPid = "pid_0090";
    const std::string targetInterface = "mi_00";
    const std::string targetCol = "";

    for (const auto& [hidPath, sddl] : hidsSddl) {
        if (hidPath.find(targetPid) != -1 && hidPath.find(targetInterface) != -1 && (targetCol.empty() || hidPath.find(targetCol) != -1)) {
            EXPECT_FALSE(sddl.empty());
        }
    }
}

TEST(CxSDDLTest, SetDeviceSACL) {
       
    //auto saclSet = cxSetSACL(R"(C:\00_RazerSpace\Code\Tool\devicesddl\x64\Release\showhidden.txt)", true);
    //EXPECT_TRUE(saclSet == ERROR_SUCCESS);

    std::string sacl;
    auto getResult = cxGetSACL(R"(C:\00_RazerSpace\Code\Tool\devicesddl\x64\Release\showhidden.txt)", sacl);
    EXPECT_TRUE(getResult == ERROR_SUCCESS);
}

TEST(CxSDDLTest, TestFileSACLAudit) {
    const char* testFile = R"(C:\temp\test_audit.txt)";
    
    // 1. 创建测试文件
    HANDLE hFile = CreateFileA(testFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile != INVALID_HANDLE_VALUE) {
        const char* content = "Initial content for SACL audit test\n";
        DWORD written;
        WriteFile(hFile, content, strlen(content), &written, NULL);
        CloseHandle(hFile);
    }
    
    // 2. 使用新的 SDDL 方法设置 SACL
    auto saclResult = cxSetSACLWithSDDL(testFile, true);
    EXPECT_EQ(saclResult, ERROR_SUCCESS) << "Failed to set SACL with SDDL, error: " << saclResult;
    
    // 如果新方法失败，尝试原方法
    if (saclResult != ERROR_SUCCESS) {
        saclResult = cxSetSACL(testFile, true);
        EXPECT_EQ(saclResult, ERROR_SUCCESS) << "Failed to set SACL with original method, error: " << saclResult;
    }
    
    // 3. 验证 SACL 设置
    std::string sacl;
    auto getResult = cxGetSACL(testFile, sacl);
    EXPECT_EQ(getResult, ERROR_SUCCESS) << "Failed to get SACL, error: " << getResult;
    EXPECT_FALSE(sacl.empty()) << "SACL should not be empty";
    
    // 输出 SACL 以便调试
    if (!sacl.empty()) {
        printf("Current SACL: %s\n", sacl.c_str());
        
        // 解析 SACL
        auto sddlInfo = cxParseSDDL(sacl);
        for (const auto& ace : sddlInfo.aces) {
            printf("ACE Type: %s, Rights: %s, SID: %s\n", 
                   ace.type.c_str(), ace.rights.c_str(), ace.account_sid.c_str());
        }
    }
    
    // 4. 执行会触发审计的操作（写入文件）
    printf("\n=== 审计测试说明 ===\n");
    printf("文件路径: %s\n", testFile);
    printf("当前 SACL: %s\n", sacl.c_str());
    printf("\n请检查以下设置：\n");
    printf("1. 运行命令检查审计策略: auditpol /get /category:\"Object Access\"\n");
    printf("2. 确保 'File System' 审计已启用\n");
    printf("3. 在 Event Viewer -> Windows Logs -> Security 中查看审计记录\n");
    printf("4. 查找事件 ID: 4656 (对象打开), 4658 (对象关闭), 4663 (访问尝试)\n\n");
    
    // 5. 模拟文件修改
    hFile = CreateFileA(testFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile != INVALID_HANDLE_VALUE) {
        const char* newContent = "=== Modified content to trigger audit ===\n";
        DWORD written;
        SetFilePointer(hFile, 0, NULL, FILE_END);
        WriteFile(hFile, newContent, strlen(newContent), &written, NULL);
        CloseHandle(hFile);
        printf("✓ 文件已修改，应该会触发审计记录\n");
        printf("✓ 请稍等片刻，然后检查 Event Viewer\n\n");
    }
    
    // 6. 再次尝试删除文件（也会触发审计）
    if (DeleteFileA(testFile)) {
        printf("✓ 文件已删除，删除操作也应该触发审计记录\n");
    }
}

TEST(CxSDDLTest, TestHIDDeviceSACLAudit) {
    // HID 设备路径 - Razer 设备
    const char* hidPath = R"(\\?\hid#vid_1532&pid_00a4&mi_00&col03&col02#b&18c9aabe&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030})";
    
    printf("\n=== HID 设备 SACL 审计测试 ===\n");
    printf("设备路径: %s\n", hidPath);
    
    // 1. 首先读取当前的 DACL 和 SACL 状态
    std::string currentSACL;
    auto getSACLResult = cxGetSACL(hidPath, currentSACL);
    if (getSACLResult == ERROR_SUCCESS) {
        printf("当前 SACL: %s\n", currentSACL.empty() ? "(空)" : currentSACL.c_str());
    } else {
        printf("读取当前 SACL 失败，错误码: %lu\n", getSACLResult);
    }
    
    // 2. 尝试设置 SACL 以审计权限修改操作
    printf("\n正在设置 HID 设备 SACL...\n");
    
    // 首先尝试专门的设备 SACL 设置函数
    auto saclResult = cxSetDeviceSACL(hidPath, true);
    
    if (saclResult == ERROR_SUCCESS) {
        printf("✓ 设备专用 SACL 设置成功\n");
    } else {
        printf("✗ 设备专用 SACL 设置失败，错误码: %lu\n", saclResult);
        
        // 尝试文件对象方法
        printf("尝试文件对象方法...\n");
        saclResult = cxSetSACL(hidPath, true);
        if (saclResult == ERROR_SUCCESS) {
            printf("✓ 文件对象方法设置 SACL 成功\n");
        } else {
            printf("✗ 文件对象方法失败，错误码: %lu\n", saclResult);
            
            // 最后尝试 SDDL 方法
            printf("尝试使用 SDDL 方法...\n");
            saclResult = cxSetSACLWithSDDL(hidPath, true);
            if (saclResult == ERROR_SUCCESS) {
                printf("✓ SDDL 方法设置 SACL 成功\n");
            } else {
                printf("✗ 所有方法都失败，错误码: %lu\n", saclResult);
            }
        }
    }
    
    // 3. 验证 SACL 设置结果
    std::string newSACL;
    auto getNewSACLResult = cxGetSACL(hidPath, newSACL);
    
    if (getNewSACLResult == ERROR_SUCCESS && !newSACL.empty()) {
        printf("\n✓ 验证 SACL 设置成功\n");
        printf("新的 SACL: %s\n", newSACL.c_str());
        
        // 解析并显示 SACL 内容
        auto sddlInfo = cxParseSDDL(newSACL);
        printf("\nSACL 解析结果:\n");
        for (const auto& ace : sddlInfo.aces) {
            printf("  ACE 类型: %s (%s)\n", ace.type.c_str(), 
                   ace.desc.type_desc.empty() ? "未知" : ace.desc.type_desc.c_str());
            printf("  权限: %s (%s)\n", ace.rights.c_str(),
                   ace.desc.rights_desc.empty() ? "未知" : ace.desc.rights_desc.c_str());
            printf("  账户: %s (%s)\n", ace.account_sid.c_str(),
                   ace.desc.account_sid_desc.empty() ? "未知" : ace.desc.account_sid_desc.c_str());
            printf("  ----\n");
        }
        
        EXPECT_FALSE(newSACL.empty()) << "SACL should not be empty after setting";
        
        // 4. 输出审计指导
        printf("\n=== 审计测试指导 ===\n");
        printf("1. 确保审计策略已启用:\n");
        printf("   auditpol /set /subcategory:\"File System\" /success:enable /failure:enable\n");
        printf("   auditpol /set /subcategory:\"Kernel Object\" /success:enable /failure:enable\n");
        printf("\n2. 现在用另一个程序修改此 HID 设备的 DACL:\n");
        printf("   设备路径: %s\n", hidPath);
        printf("\n3. 修改 DACL 后，在 Event Viewer 中查看审计记录:\n");
        printf("   位置: Windows Logs -> Security\n");
        printf("   事件 ID: 4656 (对象访问请求), 4658 (对象句柄关闭), 4670 (权限修改)\n");
        printf("   过滤条件: 搜索设备路径或 PID %d\n", GetCurrentProcessId());
        printf("\n4. 权限修改操作应该会生成包含以下信息的审计记录:\n");
        printf("   - Object Name: %s\n", hidPath);
        printf("   - Process Name: [修改DACL的程序名]\n");
        printf("   - Access Mask: 包含 WRITE_DAC (0x40000)\n");
        printf("\n✓ SACL 已设置完成，请执行 DACL 修改操作\n");
        
    } else {
        printf("✗ 验证 SACL 失败，错误码: %lu\n", getNewSACLResult);
        printf("可能原因:\n");
        printf("- 设备不存在或无法访问\n");
        printf("- 权限不足（需要管理员权限和 SeSecurityPrivilege）\n");
        printf("- HID 设备驱动不支持 SACL\n");
        
        EXPECT_FALSE(true) << "Failed to set or verify SACL for HID device";
    }
}